package pooky.client;


import java.util.ArrayList;
import java.util.Date;

import pooky.shared.Countries;
import pooky.shared.PookyStop;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class PookysTravels implements EntryPoint {

	private PookysTravelsConstants constants = GWT.create(PookysTravelsConstants.class);
	private DateTimeFormat dtf = DateTimeFormat.getFormat("dd/MM/yy");
	
	ArrayList<PookyStop> pookysStopsList = new ArrayList<PookyStop>();
	private LoginInfo loginInfo = null;
	private VerticalPanel loginPanel = new VerticalPanel();
	private Label loginLabel = new Label("Please sign in to your Google Account to access the StockWatcher application.");
	private Anchor signInLink = new Anchor("Sign In");
	private Anchor signOutLink = new Anchor("Sign Out");
	
	private VerticalPanel mainPanel = new VerticalPanel();
	private HorizontalPanel centralPanel = new HorizontalPanel();
	private HorizontalPanel buttonPanel = new HorizontalPanel();
	private FlexTable pookysStopsTable = new FlexTable();	
	
	private VerticalPanel leftPanel = new VerticalPanel();
	private VerticalPanel rightPanel = new VerticalPanel();
	
	
	private Button refreshListButton = new Button("Refresh List");
	private Button addPookyStopButton = new Button("Add");

	private final PookyStopServiceAsync pookyStopService = GWT.create(PookyStopService.class);

	private VerticalPanel informationInputPanel = new VerticalPanel();

	private HorizontalPanel locationInputPanel = new HorizontalPanel();
	private Label locationLabel = new Label(constants.location()); 
	private TextBox locationTextField = new TextBox();


	private HorizontalPanel dateInputPanel = new HorizontalPanel();
	private Label dateLabel = new Label(constants.date()); 
	private TextBox dateTextField = new TextBox();


	private HorizontalPanel coordinatesPanel = new HorizontalPanel();
	private Label latitudeLabel = new Label(constants.latitude()); 
	private TextBox latitudeTextField = new TextBox();
	private Label longitudeLabel = new Label(constants.longitude()); 
	private TextBox longitudeTextField = new TextBox();

	private HorizontalPanel zoomLevelInputPanel = new HorizontalPanel();
	private Label zoomLevelLabel = new Label(constants.zoomlevel()); 
	private TextBox zoomLevelTextField = new TextBox();

	private HorizontalPanel imagePathInputPanel = new HorizontalPanel();
	private Label imagePathLabel = new Label(constants.imagepath()); 
	private TextBox imagePathTextField = new TextBox();

	private HorizontalPanel descriptionInputPanel = new HorizontalPanel();
	private Label descriptionLabel = new Label(constants.description()); 
	private TextBox descriptionTextField = new TextBox();

	private HorizontalPanel imageSizeInputPanel = new HorizontalPanel();
	private Label imageHeightLabel = new Label(constants.imageheight()); 
	private TextBox imageHeightTextField = new TextBox();
	private Label imageWidthLabel = new Label(constants.imagewidth()); 
	private TextBox imageWidthTextField = new TextBox();

	private HorizontalPanel countryInputPanel = new HorizontalPanel();
	private Label countryLabel = new Label(constants.country()); 
	private SuggestBox countrySuggestBox = new SuggestBox(Countries.createCountriesOracle());
	

	private HorizontalPanel dayOrderInputPanel = new HorizontalPanel();
	private Label dayOrderLabel = new Label(constants.dayorder()); 
	private TextBox dayOrderTextField = new TextBox();


	public void onModuleLoad() {
		RootPanel.get("appTitle").add(new Label(constants.apptitle()));
		// Check login status using login service.
		LoginServiceAsync loginService = GWT.create(LoginService.class);
		loginService.login(GWT.getHostPageBaseURL(), new AsyncCallback<LoginInfo>() {
			public void onFailure(Throwable error) {
				handleNotLoggedInError(error);
			}

			public void onSuccess(LoginInfo result) {
				loginInfo = result;
				if(loginInfo.isLoggedIn()) {
					loadPookyMainPanel();
				} else {
					loadLogin();
				}
			}
		});
	}

	private void loadLogin() {
		// Assemble login panel.
		signInLink.setHref(loginInfo.getLoginUrl());
		loginPanel.add(loginLabel);
		loginPanel.add(signInLink);
		RootPanel.get("pookyMain").add(loginPanel);
	}

	private void loadPookyMainPanel() {

		signOutLink.setHref(loginInfo.getLogoutUrl());

		loadPookyStops();

		locationInputPanel.add(locationLabel);
		locationInputPanel.add(locationTextField);

		dateInputPanel.add(dateLabel);
		dateInputPanel.add(dateTextField);

		coordinatesPanel.add(latitudeLabel);
		coordinatesPanel.add(latitudeTextField);
		coordinatesPanel.add(longitudeLabel);
		coordinatesPanel.add(longitudeTextField);

		zoomLevelInputPanel.add(zoomLevelLabel);
		zoomLevelTextField.setText("17");
		zoomLevelInputPanel.add(zoomLevelTextField);

		imagePathInputPanel.add(imagePathLabel);
		imagePathInputPanel.add(imagePathTextField);

		descriptionInputPanel.add(descriptionLabel);
		descriptionInputPanel.add(descriptionTextField);

		imageSizeInputPanel.add(imageHeightLabel);
		imageSizeInputPanel.add(imageHeightTextField);
		imageSizeInputPanel.add(imageWidthLabel);
		imageSizeInputPanel.add(imageWidthTextField);

		countryInputPanel.add(countryLabel);		
		countryInputPanel.add(countrySuggestBox);

		dayOrderInputPanel.add(dayOrderLabel);
		dayOrderInputPanel.add(dayOrderTextField);

		informationInputPanel.add(locationInputPanel);
		informationInputPanel.add(dateInputPanel);
		informationInputPanel.add(coordinatesPanel);
		informationInputPanel.add(zoomLevelInputPanel);
		informationInputPanel.add(imagePathInputPanel);
		informationInputPanel.add(descriptionInputPanel);
		informationInputPanel.add(imageSizeInputPanel);
		informationInputPanel.add(countryInputPanel);
		informationInputPanel.add(dayOrderInputPanel);




		buttonPanel.add(addPookyStopButton);
		buttonPanel.add(refreshListButton);

		
		leftPanel.add(informationInputPanel);
		leftPanel.add(buttonPanel);
		rightPanel.add(pookysStopsTable);
		
		centralPanel.add(signOutLink);
		centralPanel.add(leftPanel);
		centralPanel.add(rightPanel);

		mainPanel.add(signOutLink);
		mainPanel.add(centralPanel);

		RootPanel.get("pookyMain").add(mainPanel);


		locationTextField.setFocus(true);







		addPookyStopButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				addPookyStop();
			}
		});

		locationTextField.addKeyPressHandler(new KeyPressHandler() {
			public void onKeyPress(KeyPressEvent event) {
				if (event.getCharCode() == KeyCodes.KEY_ENTER) {
					addPookyStop();
				}
			}
		});


		refreshListButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				loadPookyStops();
			}
		});
	}



	private void addPookyStop() {
		final String location = locationTextField.getText().trim();
		final String country = countrySuggestBox.getText();
		if (location.isEmpty()) {
			Window.alert("'" + location + "' is not a valid symbol.");
			locationTextField.selectAll();
			return;
		}
		
		Date date = null;
		try {
			date = dtf.parse(dateTextField.getText());
		} catch (IllegalArgumentException e) {
			Window.alert("'" + dateTextField.getText() + "' is not a valid date.");
			dateTextField.selectAll();
			return;
		}

		if (!Countries.countryList.contains(country)) {
			Window.alert("'" + country + "' is not a valid country.");
			return;
		}
		
		locationTextField.setFocus(true);

		final PookyStop ps = new PookyStop();
		ps.setLocation(location);
		ps.setDate(date);
		ps.setCountry(country);
		
		addPoolyStop(ps);
	}

	private void addPoolyStop(final PookyStop ps){
		pookyStopService.addPookyStop(ps, new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {

				if (error instanceof NotLoggedInException) {
					handleNotLoggedInError(error);
				}else if (error instanceof DuplicateKeyException){
					Window.alert(((DuplicateKeyException) error).getKey() + "exists already!");
				}


			}
			public void onSuccess(Void ignore) {
				displayAddedPooky(ps);
			}
		});
	}


	private void displayAddedPooky(final PookyStop ps) {
		// Add the stock to the table.
		int row = pookysStopsTable.getRowCount();
		pookysStopsList.add(ps);
		pookysStopsTable.setText(row, 0, ps.getLocation());
		pookysStopsTable.setText(row,1, dtf.format(ps.getDate()).toString());
		pookysStopsTable.setText(row,2, ps.getCountry());
		pookysStopsTable.setText(row,3, ps.getCoordinates().getLatitude().toString());
		pookysStopsTable.setText(row,4, ps.getCoordinates().getLongitude().toString());
		pookysStopsTable.setText(row,5, ps.getText());

		
		// Add a button to remove this stock from the table.
		Button removeStockButton = new Button("x");
		removeStockButton.addStyleDependentName("remove");
		removeStockButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				removePoolyStop(ps);

			}
		});
		pookysStopsTable.setWidget(row, 6, removeStockButton);


	}

	private void removePoolyStop(final PookyStop ps){
		pookyStopService.removePookyStop(ps, new AsyncCallback<Void>() {
			public void onFailure(Throwable error) {
				handleNotLoggedInError(error);
			}
			public void onSuccess(Void ignore) {
				undisplayPookyStop(ps);
			}
		});
	}

	private void undisplayPookyStop(PookyStop ps){
		int removedIndex = pookysStopsList.indexOf(ps);
		pookysStopsList.remove(removedIndex);
		pookysStopsTable.removeRow(removedIndex+1);
	}

	private void loadPookyStops() {
		pookyStopService.getPookyStops(new AsyncCallback<PookyStop[]>() {
			public void onFailure(Throwable error) {
			}
			public void onSuccess(PookyStop[] psa) {
				undisplayPookyStops();
				addTableHeaders();
				displayPookyStops(psa);
			}
		});
	}

	private void displayPookyStops(PookyStop[] psa) {
		for (PookyStop ps : psa) {
			displayAddedPooky(ps);
		}
	}


	private void addTableHeaders(){
		pookysStopsTable.setText(0, 0, constants.location());
		pookysStopsTable.setText(0, 1, constants.date());
		pookysStopsTable.setText(0, 2, constants.country());
		pookysStopsTable.setText(0, 3, constants.latitude());
		pookysStopsTable.setText(0, 4, constants.longitude());
		pookysStopsTable.setText(0, 5, constants.description());
		
		
	}

	private void undisplayPookyStops() {
		pookysStopsList.clear();
		pookysStopsTable.removeAllRows();
	}


	private void handleNotLoggedInError(Throwable error) {
		Window.alert(error.getMessage());
		if (error instanceof NotLoggedInException) {
			Window.Location.replace(loginInfo.getLogoutUrl());
		}
	}

}

